home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
packet
/
p_tapr
/
tnchst
/
dlc.c
< prev
next >
Wrap
Text File
|
1992-03-16
|
13KB
|
439 lines
/***** DATA LINK CONTROL PROTOCOL SOFTWARE (c) 1990-91 Howard Goldstein ***/
/* all rights reserved. permission for non-commercial amateur use
/* granted */
#include "dlc.inc"
/*** global variables ***/
/* storage for dlc control blocks */
struct dlccb_struct dlcbs;
byte calling_addr ; /* set in AFT_IN_H, reflects calling
addr of the last dlc frame rcvd */
extern byte mydlcnum ; /* this computer's DLC address */
void cdecl dlc_init() /* call on init */
{
dlcbs.dlc_state = DLIDLE ; /* state to idle */
dlcbs.timer = (-1) ; /* stop timer */
dlcbs.dlc_peer_addr = DEFAULT_DLC_PEER ; /* addr to call when we
initiate the dlc link */
}
/* set timer to expired and zero the retry counter - called on
state change */
void cdecl dlc_timer_retry_reset( dlccb )
struct dlccb_struct *dlccb;
{
dlccb->timer = 0 ; /* causes immediate expiration */
dlccb->retry_count = 0 ;
}
void cdecl dlc_event( event, dlccb, bframe, len)
byte event; /* as defined by preproc directives */
struct dlccb_struct * dlccb;
struct dlc_frame_struct * bframe; /* ptr to frame, if any associated w/ event */
word len; /* len " " */
{
byte nstate;
/* these are the state tables; included later, must
be identified here */
extern struct dlc_state_entry dlcs_table[][DNEVENTS];
void (*hdlr) (struct dlccb_struct *, struct dlc_frame_struct *,
word );
/* set up local vars w/ results of lookup */
nstate = dlcs_table[dlccb->dlc_state - 1][event].newstate ;
hdlr = dlcs_table[dlccb->dlc_state - 1][event].action_handler ;
#if DLC_EVENT_TRACE
printf("dlc event %d old state %d new state %d\n",event,dlccb->dlc_state,
nstate);
#endif
/* if new state is mentioned and diff from the
current state */
if ( nstate && nstate != dlccb->dlc_state)
{
dlc_timer_retry_reset( dlccb ); /* reset timer, try */
dlccb->dlc_state = nstate ; /* change state */
}
if ( hdlr ) /* if a handler was defined */
(*hdlr) (dlccb,bframe,len) ; /* then run it */
}
/* call on timer tick intervals - updates and signals expiration
events */
void cdecl dlc_timer_tick()
{
byte x;
if ( dlcbs.dlc_state != DLIDLE /* if not idle and */
&& dlcbs.timer >= 0 ) /* timer not stopped */
{ /* then count time pd - */
if ( ( --dlcbs.timer < 1 ) ) /* if now expired */
{ /* then signal event*/
/* force timer to stay expired */
--dlcbs.timer ;
/* count retry */
if ( dlcbs.retry_count++ == DLC_MAX_TRIES )
/* if retry lim excdd then LRETRY event*/
dlc_event( D_RETRYX, &dlcbs, NULL, 0 );
else
/* else TIMER event, */
/* type event depends on
whether in supvy state or
not */
dlc_event( D_TIMERX, &dlcbs, NULL, 0 );
}
}
}
/* initialize dlccb data machine, ptrs etc */
void cdecl dlc_data_init( dlccb )
struct dlccb_struct *dlccb;
{
dlccb->dlctxseq = dlccb->dlcrxseq = dlccb->outstanding = 0 ;
dlccb->dl_next.next = NULL ; /* clr linked list ptr */
}
void cdecl send_dlc_fr( dlccb, dlc_cmd, info, len)
struct dlccb_struct *dlccb;
byte dlc_cmd ; /* cmd byte */
byte *info;
word len;
{
struct itm_struct *itm ; /* aft sender eats itms */
byte *insertptr ; /* ptr to insert data */
int retval ; /* holds success value to return
when allocated an itm ok */
/* allocate an intertask msg - if couldnt allcoate */
if ( ! (itm = (struct itm_struct *)
malloc(AFTMAXFRAMESIZE + sizeof( struct itm_struct ) ) ) )
; /*then do nothing */
else /* else was able to allocate, no problem */
{
itm->msg_len = len+1 ; /* length is size of data +
size of no-addrs header */
insertptr = itm->itm_data ; /* pointer we'll bld packet to */
if ( mydlcnum ) /* if we have a dlc address then */
{ /* need to stuff the addresses */
*insertptr++ = dlccb->dlc_peer_addr ; /* stuff dest*/
*insertptr++ = mydlcnum ; /* stuff ours (src)*/
itm->msg_len += 2 ; /* adj size for the
2 addr bytes */
}
*insertptr++ = dlc_cmd ; /* insert cmd byte */
memcpy( insertptr, info, len ) ; /* move data */
aftt_send( itm ); /* now try to send the frame */
free( (char *) itm ); /* and free it once it's done */
}
}
void cdecl send_resetack(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
send_dlc_fr( dlccb, 0x20, NULL, 0);
}
void cdecl send_dlcdack(dlccb,bframe,len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
send_dlc_fr( dlccb, 0x50 + dlccb->dlcrxseq, NULL, 0);
}
void cdecl dlc_ring_in(dlccb, bframe, len )
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
dlc_data_init( dlccb ); /* init data */
dlccb->dlc_state = DLDATA; /* indicate state is data - all rdy to go */
dlccb->dlc_peer_addr = calling_addr ; /* stuff the calling dlc's addr */
send_resetack( dlccb, NULL, 0);
/* and ack the reset */
}
/* estabs outgoing */
void cdecl dlc_ring_out(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
dlc_data_init(dlccb); /* init data is all tts required. state
table takes care of timers etc */
}
void cdecl dlc_retryfail(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
dlccb->retry_count = 0 ; /** FOREVER RETRY **/
}
void cdecl dlc_retryreset(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
send_dlc_fr( dlccb, 0x10, NULL, 0 );
dlccb->timer = DLC_RETRY_TIME ;
}
void cdecl dlc_senddata(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
byte ts; /* transmit sequence # holder */
struct dl_data_struct *pkt ; /* point to data to send */
ts = dlccb->dlctxseq ; /* starting tx seq # */
pkt = &dlccb->dl_next ; /* points to oldest outstand
ing packet, if !null */
/* now traverse the linked list of pktzd xmit data */
while ( pkt->next ) /* while pkt in the list */
{
pkt = pkt->next ; /* traverse to next pkt */
/* send the packet */
send_dlc_fr( dlccb, 0x40 + ts, pkt->data, pkt->len );
ts = ( ( ts+1 ) & 15 ); /* next seq #, mod 16 */
}
/*endwhile */
dlccb->timer = DLC_RETRY_TIME ; /* restart timer */
}
void cdecl dlc_dataproc(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
if ( (bframe->cmd & 15) == dlccb->dlcrxseq ) /* if seq # matches */
{
if ( dlc_data_handler( bframe->data,
len-1 ) ) /* if upper level
toook the frame */
{
/* mod16 bump*/
dlccb->dlcrxseq = ( (dlccb->dlcrxseq+1) & 15 );
send_dlcdack( dlccb, NULL, 0 ); /*then send ack, */
}
else /* upper level could not take the frame */
/* send_dbusy( dlccb, NULL, 0 ); /* send busy */
send_dlcdack( dlccb, NULL, 0 ); /* send busy */
}
else /* else seq # didnt match */
send_dlcdack( dlccb, NULL,0 ); /* send what we do hv */
}
void cdecl dlc_ackproc(dlccb, bframe, len)
struct dlccb_struct *dlccb;
struct dlc_frame_struct *bframe;
word len;
{
byte ackseq, nacked; /* remote acks to seq ackseq, nacked
# of packets */
struct dl_data_struct *ptr; /* use to delete packets from
head of linked list */
dlccb->retry_count = 0 ; /* reset retry count */
ackseq = ( bframe->cmd & 15 ) ; /* strip off seq #, mod 16 */
nacked = ( ackseq - dlccb->dlctxseq ) & 15 ; /* he acks this many */
if ( nacked > dlccb->outstanding ) /* if too many */
printf("*** error- too many acked\n"); /* need to do error!*/
else /* else no problem */
{
if ( dlccb->outstanding > 0 ) /* if packets were outsdng */
{
dlccb->dlctxseq = ackseq ; /* update tx seq # */
if ( (dlccb->outstanding-=nacked) == 0 ) /* if all ackd */
dlc_event( D_ALL_ACK, dlccb, NULL, 0) ; /* then gen event */
while ( nacked-- ) /* while packets left to release */
{
ptr = dlccb->dl_next.next->next ;
/* link to 2d packet */
free( (char *) dlccb->dl_next.next ); /* free 1st packet */
dlccb->dl_next.next = ptr ; /* make 2d pkt the 1st in the
head record */
} /*endwhile packets left to release*/
} /*endif outstanding packets */
} /*endif else */
}
/** called from underlying AFT receiver **/
/** converts AFT frames into events and runs the event handler **/
void cdecl aft_in_handler( bframe, len )
struct dlc_frame_struct *bframe;
word len;
{
byte event ; /* will convert dlc cmd to event */
byte dest ; /* temp holders for dlc source and dest vals*/
int x ;
struct dlccb_struct *dlccb ;
/* do (conditional) address checking */
if ( mydlcnum ) /* check addresses? only if set */
{
dest = bframe->cmd ; /* load up the misplaced addr holders */
calling_addr = bframe->data[0] ;
/* if dest addr doesnt match */
if ( dest != mydlcnum && dest != GLOBALDLC )
return ; /* then return/ DROP THE PACKET ON
THE FLOOR */
/* else we should process it - first gotta remove
the address fields from this pseudo-union */
len -= 2 ; /* remove addr bytes from len */
/* and use inefficient move */
memcpy( (char *) bframe, (char *) bframe + 2 , len );
} /* endif addr check */
/* force the dlccb for this lcn */
dlccb = &dlcbs;
if ( dlccb->dlc_state == DLIDLE ) /* if not connected */
switch( bframe->cmd ) /* then what kind of cmd? */
{
case 0x10:
/* kluge to get around need
to know dlccb in event tables */
dlc_ring_in( NULL, bframe, len );
break ;
default:
break; /* ignore others */
}
else
{
switch ( bframe->cmd & 0xF0 ) /* on command, */
{
case 0x10: event = D_RX_RESET; break;
case 0x20: event = D_RX_RESET_ACK; break;
case 0x40: event = D_RX_DATA; break;
case 0x50: event = D_RX_ACK; break;
default:
printf("$%02X unknown DLC cmd\n",bframe->cmd);
return;
break;
}
/* dispatch event only when dlccb is known */
dlc_event( event, dlccb, bframe, len );
} /* endif */
}
/*************************************************************
Interface : BLP>dlc
**************************************************************/
/** initiate a dlc link;no parms, no return **/
void
dlc_start_cmd( )
{
dlc_event( D_LSTART, &dlcbs, NULL, 0 ) ; /* try to start 'er up */
}
/* send data on the dlc. returns TRUE if
sent ok */
int cdecl dlc_data_cmd( data, len )
byte *data;
word len;
{
/* vars needed to build and add to linked list */
struct dl_data_struct *newpacket, *ptr;
struct dlccb_struct *dlccb;
dlccb = &dlcbs; /* init for only dlcb */
if ( dlccb->outstanding < DLC_MAX_OUTSTANDING /*if able to pktz more */
&& dlccb->dlc_state >= DLDATA /* and in a data state */
&& ( newpacket = (struct dl_data_struct *)
malloc(sizeof(struct dl_data_struct)) ) )
/* and able to allocate then */
{
newpacket->len = len ; /* set up len field */
memcpy(newpacket->data,data,len); /* set up data */
newpacket->next = NULL ; /* init link field */
/* now add to tail of linked list */
ptr = &dlccb->dl_next ; /*1st, ptt to hdr dummy struct */
while ( ptr->next ) /* while not at end of list */
ptr = ptr->next ; /* traverse */
/*now merely put ptr to new packet at end of list link*/
ptr->next = newpacket;
dlccb->outstanding++;
/* signal new data */
dlc_event( D_Q_DATA, dlccb, NULL, 0);
return( TRUE );
} else return (FALSE);
}
/*************************************************************
Interface : dlc>blp
**************************************************************/
/* variable - hold dlccb pointers for each channel */
/*** should return TRUE if able to accept data ***/
int cdecl dlc_data_handler( data, len )
byte *data;
word len;
{
dlc_in_handler( (struct bframe_struct *) data, len);
/* ship it to BLP */
return( TRUE ); /* always return true in this intfc */
}
/* get state tables */
#include "dlctables.c"